#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>
#include <string>
#include <iomanip>


// Function to calculate divided differences for truncated power functions
double computeDividedDifference(int degree, const std::vector<double>& knots, double x) {
    std::vector<double> dividedDifferences = knots;

    for (size_t i = 0; i < knots.size(); ++i) {
        dividedDifferences[i] = (knots[i] - x >= 0) ? std::pow(knots[i] - x, degree) : 0;
    }

    for (size_t level = 1; level < knots.size(); ++level) {
        for (size_t i = knots.size() - 1; i >= level; --i) {
            dividedDifferences[i] = (dividedDifferences[i] - dividedDifferences[i - 1]) / (knots[i] - knots[i - level]);
        }
    }

    return dividedDifferences.back();
}

// Helper function to save x and y data to a CSV file
void saveDataToCSV(const std::string& filename, const std::vector<double>& xValues, const std::vector<double>& yValues) {
    std::ofstream file(filename + ".csv");
    if (!file) {
        std::cerr << "Error: Unable to open file " << filename << std::endl;
        return;
    }

    for (size_t i = 0; i < xValues.size(); ++i) {
        file << xValues[i] << "," << yValues[i] << "\n";
    }
}

// Generate data for truncated power functions
void generateTruncatedPowerData(int degree, const std::vector<double>& knots, const std::vector<double>& xValues, const std::string& prefix) {
    for (size_t start = 0; start < knots.size(); ++start) {
        for (size_t end = start; end < knots.size(); ++end) {
            std::vector<double> subKnots(knots.begin() + start, knots.begin() + end + 1);
            std::vector<double> yValues;

            for (double x : xValues) {
                yValues.push_back(computeDividedDifference(degree, subKnots, x));
            }

            saveDataToCSV(prefix + std::to_string(start) + "_" + std::to_string(end), xValues, yValues);
        }
    }
}

int main() {
    // Define knot sets for degree 1 and 2
    const std::vector<double> knotsDegree1 = {0, 1, 2};
    const std::vector<double> knotsDegree2 = {0, 1, 2, 3};

    // Generate x-values for plotting
    std::vector<double> xValuesDegree1;
    for (double x = -1.0; x <= 3.0; x += 0.01) {
        xValuesDegree1.push_back(x);
    }

    std::vector<double> xValuesDegree2;
    for (double x = -1.0; x <= 4.0; x += 0.01) {
        xValuesDegree2.push_back(x);
    }

    // Generate data for degree 1
    generateTruncatedPowerData(1, knotsDegree1, xValuesDegree1, "data_F_n1_");

    // Generate data for degree 2
    generateTruncatedPowerData(2, knotsDegree2, xValuesDegree2, "data_F_n2_");

    std::cout << "Data generation completed. Files are saved " << std::endl;
    return 0;
}
